Skip to content

Conversation

mnocon
Copy link
Contributor

@mnocon mnocon commented Jun 10, 2025

@github-actions
Copy link

github-actions bot commented Jun 10, 2025

@mnocon mnocon force-pushed the discounts-rest branch 2 times, most recently from 35978c8 to 636c53c Compare June 10, 2025 22:12
@mnocon mnocon marked this pull request as ready for review June 11, 2025 06:37
@mnocon mnocon requested a review from a team June 11, 2025 07:25
@ezrobot ezrobot requested review from adriendupuis, dabrt and julitafalcondusza and removed request for a team June 11, 2025 07:26
mnocon and others added 4 commits June 11, 2025 13:03
* [Discounts] Added event reference

* Fixed links

* Fixes before review

* Removed column
* Mentioned discounts in pricing and customer groups

* Before review fixes

* Added mention to the PIM guide
* Permissions

* Build fixes

* Fixed links

* Fixed last links

* Removed link

* Apply suggestions from code review

Co-authored-by: julitafalcondusza <[email protected]>

---------

Co-authored-by: julitafalcondusza <[email protected]>
* Added update instructions

* Fixed link
Base automatically changed from discounts to 4.6 June 11, 2025 13:51
Copy link
Contributor

@adriendupuis adriendupuis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some error responses are missing but this isn't really important.

JSON object type description is incomplete as the wrapped XML part isn't accessible.

Comment on lines +36 to +41
responses:
200:
body:
application/vnd.ibexa.api.Discount+json:
type: DiscountWrapper
example: !include examples/discounts/POST/DiscountCreateResponse.json.example
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is likely some error responses as well. Probably 403 if user haven't the rights to create a discount and 500 if the payload is malformed.
It might not worth spending too much time into completing this in 4.6 RAML. It will be more important in 5.0 OpenAPI.
Remember https://redocly.com/docs/cli/rules/oas/operation-4xx-response 😉

Comment on lines 6317 to 6385
DiscountListWrapper:
type: object
description: 'Wrapper object for DiscountList.'
properties:
DiscountList:
type: DiscountList
description: 'Object containing a list of discounts.'

DiscountList:
type: object
description: 'Object containing a list of discounts.'
properties:
Discount:
type: array
items:
type: object
properties:
identifier:
type: string
description: "Discount identifier."
type:
type: string
description: "Discount type: cart or catalog."
priority:
type: integer
description: "Discount priority."
isEnabled:
type: boolean
description: "Indicates whether the discount is enabled."
userId:
type: integer
description: "User ID of discount creator."
rule:
type: object
description: "Describes how the discount is calculated: percentage or fixed."
properties:
type:
type: string
description: "Discount type."
amount:
type: integer
description: "Discount amount."
startDate:
type: datetime
description: "Defines when the discount starts."
endDate:
type: datetime
description: "Defines when the discount starts."
translations:
type: array
description: "Translations of discount data."
items:
type: object
properties:
languageCode:
type: string
name:
type: string
description:
type: string
label:
type: string
labelDescription:
type: string
conditions:
type: array
description: "List of discount conditions."
items:
type: DiscountCondition
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As only JSON is used, DiscountList can't be displayed.

When there is both, this no big deal that the Wrapper description is short, just close the JSON Wrapper type description and open the XML type description.
image

But here, there is no such possibility.
image

I would move DiscountList under its wrapper.

Suggested change
DiscountListWrapper:
type: object
description: 'Wrapper object for DiscountList.'
properties:
DiscountList:
type: DiscountList
description: 'Object containing a list of discounts.'
DiscountList:
type: object
description: 'Object containing a list of discounts.'
properties:
Discount:
type: array
items:
type: object
properties:
identifier:
type: string
description: "Discount identifier."
type:
type: string
description: "Discount type: cart or catalog."
priority:
type: integer
description: "Discount priority."
isEnabled:
type: boolean
description: "Indicates whether the discount is enabled."
userId:
type: integer
description: "User ID of discount creator."
rule:
type: object
description: "Describes how the discount is calculated: percentage or fixed."
properties:
type:
type: string
description: "Discount type."
amount:
type: integer
description: "Discount amount."
startDate:
type: datetime
description: "Defines when the discount starts."
endDate:
type: datetime
description: "Defines when the discount starts."
translations:
type: array
description: "Translations of discount data."
items:
type: object
properties:
languageCode:
type: string
name:
type: string
description:
type: string
label:
type: string
labelDescription:
type: string
conditions:
type: array
description: "List of discount conditions."
items:
type: DiscountCondition
DiscountListWrapper:
type: object
description: 'Wrapper object for DiscountList.'
properties:
DiscountList:
type: object
description: 'Object containing a list of discounts.'
properties:
Discount:
type: array
items:
type: object
properties:
identifier:
type: string
description: "Discount identifier."
type:
type: string
description: "Discount type: cart or catalog."
priority:
type: integer
description: "Discount priority."
isEnabled:
type: boolean
description: "Indicates whether the discount is enabled."
userId:
type: integer
description: "User ID of discount creator."
rule:
type: object
description: "Describes how the discount is calculated: percentage or fixed."
properties:
type:
type: string
description: "Discount type."
amount:
type: integer
description: "Discount amount."
startDate:
type: datetime
description: "Defines when the discount starts."
endDate:
type: datetime
description: "Defines when the discount starts."
translations:
type: array
description: "Translations of discount data."
items:
type: object
properties:
languageCode:
type: string
name:
type: string
description:
type: string
label:
type: string
labelDescription:
type: string
conditions:
type: array
description: "List of discount conditions."
items:
type: DiscountCondition

Same for every JSON-only object types below…

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I should have test the result on my own, it's disapointing
image

I see no issue on RAML. It looks like a limitation of raml2html itself or the templates we use with it.

Copy link
Contributor

@adriendupuis adriendupuis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@adriendupuis adriendupuis self-requested a review June 16, 2025 07:41
mnocon and others added 3 commits June 16, 2025 09:42
* [Discounts] Described Discounts API
* Apply suggestions from code review

---------

Co-authored-by: Adrien Dupuis <[email protected]>
* [Discounts] Configuration
* Apply suggestions from code review

---------

Co-authored-by: Adrien Dupuis <[email protected]>
@github-actions
Copy link

code_samples/ change report

Before (on target branch)After (in current PR)

code_samples/discounts/src/Command/ManageDiscountsCommand.php


code_samples/discounts/src/Command/ManageDiscountsCommand.php

docs/discounts/discounts_api.md@118:``` php hl_lines="60-66 68-92"
docs/discounts/discounts_api.md@119:[[= include_file('code_samples/discounts/src/Command/ManageDiscountsCommand.php') =]]
docs/discounts/discounts_api.md@120:```

001⫶<?php
002⫶
003⫶declare(strict_types=1);
004⫶
005⫶namespace App\Command;
006⫶
007⫶use DateTimeImmutable;
008⫶use Ibexa\Contracts\Core\Collection\ArrayMap;
009⫶use Ibexa\Contracts\Core\Repository\PermissionResolver;
010⫶use Ibexa\Contracts\Core\Repository\UserService;
011⫶use Ibexa\Contracts\Discounts\DiscountServiceInterface;
012⫶use Ibexa\Contracts\Discounts\Value\DiscountType;
013⫶use Ibexa\Contracts\Discounts\Value\Struct\DiscountCreateStruct;
014⫶use Ibexa\Contracts\Discounts\Value\Struct\DiscountTranslationStruct;
015⫶use Ibexa\Contracts\DiscountsCodes\DiscountCodeServiceInterface;
016⫶use Ibexa\Contracts\DiscountsCodes\Value\Struct\DiscountCodeCreateStruct;
017⫶use Ibexa\Discounts\Value\DiscountCondition\IsInCurrency;
018⫶use Ibexa\Discounts\Value\DiscountCondition\IsInRegions;
019⫶use Ibexa\Discounts\Value\DiscountCondition\IsProductInArray;
020⫶use Ibexa\Discounts\Value\DiscountRule\FixedAmount;
021⫶use Ibexa\DiscountsCodes\Value\DiscountCondition\IsValidDiscountCode;
022⫶use Symfony\Component\Console\Command\Command;
023⫶use Symfony\Component\Console\Input\InputInterface;
024⫶use Symfony\Component\Console\Output\OutputInterface;
025⫶
026⫶final class ManageDiscountsCommand extends Command
027⫶{
028⫶ protected static $defaultName = 'discounts:manage';
029⫶
030⫶ private DiscountServiceInterface $discountService;
031⫶
032⫶ private DiscountCodeServiceInterface $discountCodeService;
033⫶
034⫶ private PermissionResolver $permissionResolver;
035⫶
036⫶ private UserService $userService;
037⫶
038⫶ public function __construct(
039⫶ UserService $userSerice,
040⫶ PermissionResolver $permissionResolver,
041⫶ DiscountServiceInterface $discountService,
042⫶ DiscountCodeServiceInterface $discountCodeService
043⫶ ) {
044⫶ $this->userService = $userSerice;
045⫶ $this->discountService = $discountService;
046⫶ $this->discountCodeService = $discountCodeService;
047⫶ $this->permissionResolver = $permissionResolver;
048⫶
049⫶ parent::__construct();
050⫶ }
051⫶
052⫶ protected function execute(InputInterface $input, OutputInterface $output): int
053⫶ {
054⫶ $this->permissionResolver->setCurrentUserReference(
055⫶ $this->userService->loadUserByLogin('admin')
056⫶ );
057⫶
058⫶ $now = new DateTimeImmutable();
059⫶
060❇️ $discountCodeCreateStruct = new DiscountCodeCreateStruct(
061❇️ 'summer10',
062❇️ null, // Unlimited usage
063❇️ $this->permissionResolver->getCurrentUserReference()->getUserId(),
064❇️ $now
065❇️ );
066❇️ $discountCode = $this->discountCodeService->createDiscountCode($discountCodeCreateStruct);
067⫶
068❇️ $discountCreateStruct = new DiscountCreateStruct();
069❇️ $discountCreateStruct
070❇️ ->setIdentifier('discount_identifier')
071❇️ ->setType(DiscountType::CART)
072❇️ ->setPriority(10)
073❇️ ->setEnabled(true)
074❇️ ->setUser($this->userService->loadUserByLogin('admin'))
075❇️ ->setRule(new FixedAmount(10))
076❇️ ->setStartDate($now)
077❇️ ->setConditions([
078❇️ new IsInRegions(['germany', 'france']),
079❇️ new IsProductInArray(['product-1', 'product-2']),
080❇️ new IsInCurrency('EUR'),
081❇️ new IsValidDiscountCode($discountCode->getCode(), $discountCode->getUsedLimit()),
082❇️ ])
083❇️ ->setTranslations([
084❇️ new DiscountTranslationStruct('eng-GB', 'Discount name', 'This is a discount description', 'Promotion Label', 'Promotion Description'),
085❇️ new DiscountTranslationStruct('ger-DE', 'Discount name (German)', 'Description (German)', 'Promotion Label (German)', 'Promotion Description (German)'),
086❇️ ])
087❇️ ->setEndDate(null) // Permanent discount
088❇️ ->setCreatedAt($now)
089❇️ ->setUpdatedAt($now)
090❇️ ->setContext(new ArrayMap(['custom_context' => 'custom_value']));
091❇️
092❇️ $this->discountService->createDiscount($discountCreateStruct);
093⫶
094⫶ return Command::SUCCESS;
095⫶ }
096⫶}

Download colorized diff

@adriendupuis adriendupuis merged commit e531aa3 into 4.6 Jun 16, 2025
7 checks passed
@adriendupuis adriendupuis deleted the discounts-rest branch June 16, 2025 10:06
adriendupuis added a commit that referenced this pull request Jun 16, 2025
* [Discounts] Described Discounts API (#2783)
* [Discounts] Configuration (#2781)

---------

Co-authored-by: Adrien Dupuis <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants